package com.example.demo.securitylogin;

import com.example.demo.entity.User;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;

/**
 * springSecurity需要使用一个服务对象
 * springSecurity提供了一个服务接口，命名为：UserDetailsService
 * 其中，定义了唯一的认证方法。命名为loadUserByUsername
 * 方法，代表用户认证
 * 抛出异常。UsernameNotFoundException：代表用户查询失败时，抛出
 *  用户查询只是作为条件查询用户
 * security框架内部自动匹配密码是否正确的时候，一定要加密及解密处理
 *  要求spring容器中，必须存在一个passwordEncoder实现类
 *  对象中，提供加密逻辑和解密逻辑，解密逻辑不是反向计算明文，而是要求，
 *  实现明文和密文的验证，解密验证可以，加密验证可以
 */
@Component("myUserServiceImpl")
public class UserServiceImpl implements UserDetailsService {

    @Autowired
    private UserService userService;

    /**
     *  
     * @param username 
     * @author 陈先生
     * @date 2021/4/2 11:29
     * @return org.springframework.security.core.userdetails.UserDetails
     * @throws 
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        System.out.println("这是用户名认证逻辑，传递的用户名是："+username);
        User user = userService.login(username);
        if(null==user){
//            查询失败，用户名不存在，抛出异常。
            throw new UsernameNotFoundException("用户名不存在");
        }
        System.out.println("这是用户认证逻辑，登录的用户是"+user);
        /**
         * 查询成功，用户储存。需要匹配用户名密码是否一致。
         * 匹配密码，是由SpringSecurity内部逻辑自动完成，只需要把查询的用户名正确的密码返回即可。
         * 返回结果是UserDetails类型的实现类。可以自定义，也可以使用Security提供的实现类。
         * security框架提供的UserDetails接口的实现类型User，构造的时候，需要提供3个参数，或是7个参数
         * AuthorityUtils-->工具类，可以通过字符串创建权限集合
         */
        List<String> roles=userService.selectRoleByUserId(user);
        List<String> resources=userService.selectRoleResByUserId(user);
        /**
         * 在springSecurity中，对角色的命名有严格的规定。要求角色名称的前缀必须是”ROLE_“，不要再数据库中保存ROLE_+角色名。
         *在spring Security中，角色和权限是平等的，都代表用户的访问权限。
         */
        String [] authenticated=new String[roles.size()+resources.size()];
        for(int i=0;i<roles.size();i++){
            authenticated[i]= "ROLE_"+ roles.get(i);
        }
        for(int i=0;i<resources.size();i++){
            authenticated[roles.size()+i]=resources.get(i);
        }
        System.out.println("用户名："+user.getUsername()+"权限名称："+ Arrays.toString(authenticated));
        org.springframework.security.core.userdetails.User result =
                new org.springframework.security.core.userdetails.User(
                        username,user.getPassword(), AuthorityUtils.createAuthorityList(authenticated)
                );
        return result;
    }
}
